package customer.design.dispatcher.dispatchermode.real.aware;

import customer.design.dispatcher.dispatchermode.real.annotation.Business;
import customer.design.dispatcher.dispatchermode.real.busenum.BusinessTypeEnum;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.thymeleaf.util.MapUtils;

import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;

/**
 * 第一步 扫描bean对应的注解，获取到 AbstractBiz 所有的实现类上带有注解的 bean对象
 * 第二步  根据注解匹配到的实现类创建出AbstractBiz对象
 * 第三步 在AbstractBiz实现类中，通过execute中调用buildBean创建不同的对象 例如：ChatBean，同时调用callBiz方法由各自的实现类完成不同的业务
 * 如此一来，就达到了优化if-else方法的目的
 * @author ldanniel
 */
@Component
public class MyContextUtil implements ApplicationContextAware {
    private static  ApplicationContext applicationContext;
    private static Map<String, Object> instanceMap = new HashMap<>();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        MyContextUtil.applicationContext = applicationContext;
    }

    /**
     * 懒汉式：根据需要去扫描注解
     *
     * @param annotationType 注解Class
     * @return 带有注解的类信息
     */
    public static Map<String, Object> getBeanAnnotation(Class<? extends Annotation> annotationType) {
        return applicationContext.getBeansWithAnnotation(annotationType);
    }

    /**
     * 扫描 与 tranCode 和 type想匹配的所有带Business注解的类，通过该类去创建对象
     *
     * @param tranCode 交易类型
     * @param type     type类型
     * @param <T>      Bean 对象
     * @return Bean对象
     */
    public static <T> T getBeanName(String tranCode, String type) {
        //按需要扫描
        if (MapUtils.isEmpty(instanceMap)) {
            instanceMap = getBeanAnnotation(Business.class);
        }
        for (Map.Entry<String, Object> entry : instanceMap.entrySet()) {
            Class<?> cls = entry.getValue().getClass();
            Business annotation = cls.getAnnotation(Business.class);
            BusinessTypeEnum typeEnum = annotation.value();
            if (typeEnum.getType().equalsIgnoreCase(type) && typeEnum.getCode().equalsIgnoreCase(tranCode)) {
                return (T) applicationContext.getBean(entry.getKey(), applicationContext.getBean(entry.getKey()));
            }
        }
        return null;
    }
}
